class ResourceCrawler {
  constructor() {
    this.currentTab = 'images';
    this.resources = {
      images: [],
      videos: [],
      audios: []
    };
    this.observer = null;
    this.isScanning = false;
    this.scanTimeout = null;
    
    // 确保DOM加载完成后初始化
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => this.init());
    } else {
      this.init();
    }
  }

  init() {
    // 立即创建按钮
    this.createButton();
    this.createDrawer();

    // 页面完全加载后初始化观察器和扫描资源
    window.addEventListener('load', () => {
      if (this.drawer.classList.contains('open')) {
        this.initMutationObserver();
        this.scanResources();
      }
    });

    // 监听抽屉状态变化
    this.drawer.addEventListener('transitionend', () => {
      if (this.drawer.classList.contains('open')) {
        this.initMutationObserver();
        this.scanResources();
      } else {
        this.disconnectObserver();
      }
    });
  }

  createButton() {
    // 移除可能存在的旧按钮
    const existingButton = document.querySelector('.crawler-btn');
    if (existingButton) {
      existingButton.remove();
    }

    const button = document.createElement('button');
    button.className = 'crawler-btn';
    button.textContent = '网页爬虫';
    button.addEventListener('click', () => this.toggleDrawer());
    
    // 确保按钮添加到页面
    if (document.body) {
      document.body.appendChild(button);
    } else {
      // 如果body还不存在，等待DOM加载完成
      document.addEventListener('DOMContentLoaded', () => {
        document.body.appendChild(button);
      });
    }
  }

  createDrawer() {
    const existingDrawer = document.querySelector('.crawler-drawer');
    if (existingDrawer) return;

    const drawer = document.createElement('div');
    drawer.className = 'crawler-drawer';
    
    const content = document.createElement('div');
    content.className = 'drawer-content';
    
    const tabs = document.createElement('div');
    tabs.className = 'tab-container';
    
    const tabNames = ['图片', '视频', '音频'];
    const tabKeys = ['images', 'videos', 'audios'];
    
    const fragment = document.createDocumentFragment();
    tabNames.forEach((name, index) => {
      const tab = document.createElement('button');
      tab.className = `tab ${index === 0 ? 'active' : ''}`;
      tab.textContent = name;
      tab.addEventListener('click', () => this.switchTab(tabKeys[index]));
      fragment.appendChild(tab);
    });
    tabs.appendChild(fragment);
    
    const resourceContainer = document.createElement('div');
    resourceContainer.className = 'resource-container';
    
    const downloadAllBtn = document.createElement('button');
    downloadAllBtn.className = 'download-all-btn';
    downloadAllBtn.textContent = '下载全部';
    downloadAllBtn.addEventListener('click', () => this.downloadAll());
    
    content.appendChild(tabs);
    content.appendChild(resourceContainer);
    content.appendChild(downloadAllBtn);
    drawer.appendChild(content);
    document.body.appendChild(drawer);
    
    this.drawer = drawer;
    this.resourceContainer = resourceContainer;
  }

  initMutationObserver() {
    if (this.observer) {
      this.observer.disconnect();
    }

    this.observer = new MutationObserver(this.throttle((mutations) => {
      let shouldUpdate = false;
      for (const mutation of mutations) {
        // 只检查直接相关的变化
        if (this.isMediaElement(mutation.target) || 
            this.hasMediaChildren(mutation.addedNodes)) {
          shouldUpdate = true;
          break;
        }
      }
      if (shouldUpdate && this.drawer.classList.contains('open')) {
        this.scanResources();
      }
    }, 1000));

    // 优化观察配置
    const config = {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ['src', 'data-src'],
      characterData: false
    };

    this.observer.observe(document.body, config);
  }

  disconnectObserver() {
    if (this.observer) {
      this.observer.disconnect();
      this.observer = null;
    }
  }

  throttle(func, limit) {
    let inThrottle;
    return (...args) => {
      if (!inThrottle) {
        func.apply(this, args);
        inThrottle = true;
        setTimeout(() => inThrottle = false, limit);
      }
    };
  }

  debounce(func, wait) {
    let timeout;
    return (...args) => {
      clearTimeout(timeout);
      timeout = setTimeout(() => func.apply(this, args), wait);
    };
  }

  isMediaElement(node) {
    return node.nodeType === Node.ELEMENT_NODE && 
           (node.tagName === 'IMG' || 
            node.tagName === 'VIDEO' || 
            node.tagName === 'AUDIO' || 
            node.tagName === 'SOURCE');
  }

  hasMediaChildren(nodes) {
    for (const node of nodes) {
      if (node.nodeType === Node.ELEMENT_NODE) {
        if (this.isMediaElement(node)) return true;
        if (node.querySelector('img, video, audio, source')) return true;
      }
    }
    return false;
  }

  toggleDrawer() {
    const isOpening = !this.drawer.classList.contains('open');
    this.drawer.classList.toggle('open');
    
    if (isOpening) {
      this.scanResources();
    } else {
      this.disconnectObserver();
    }
  }

  switchTab(tab) {
    if (this.currentTab === tab) return;
    this.currentTab = tab;
    document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
    document.querySelector(`.tab:nth-child(${['images', 'videos', 'audios'].indexOf(tab) + 1})`).classList.add('active');
    this.renderResources();
  }

  async scanResources() {
    if (this.isScanning) return;
    this.isScanning = true;

    clearTimeout(this.scanTimeout);
    this.scanTimeout = setTimeout(async () => {
      try {
        this.showLoading();
        await this.performScan();
        this.renderResources();
      } finally {
        this.isScanning = false;
      }
    }, 300);
  }

  async performScan() {
    const scanPromises = [
      this.scanImages(),
      this.scanVideos(),
      this.scanAudios()
    ];

    await Promise.all(scanPromises);
  }

  async scanImages() {
    const images = new Set();
    
    // 使用 requestIdleCallback 在浏览器空闲时处理
    await new Promise(resolve => {
      requestIdleCallback(() => {
        // 扫描 img 标签
        document.querySelectorAll('img').forEach(img => {
          const url = img.src || img.dataset.src;
          if (url && url.startsWith('http')) {
            images.add({
              url,
              type: 'image',
              name: this.getFileName(url),
              size: '获取中...'
            });
          }
        });

        // 扫描背景图片
        document.querySelectorAll('[style*="background-image"]').forEach(el => {
          const match = el.style.backgroundImage.match(/url\(['"](.+?)['"]\)/);
          if (match && match[1].startsWith('http')) {
            images.add({
              url: match[1],
              type: 'image',
              name: this.getFileName(match[1]),
              size: '获取中...'
            });
          }
        });

        resolve();
      });
    });

    this.resources.images = Array.from(images);
  }

  async scanVideos() {
    const videos = new Set();

    await new Promise(resolve => {
      requestIdleCallback(() => {
        // 扫描视频元素
        const videoElements = document.querySelectorAll('video, video source, [data-video-url], [data-video-src]');
        videoElements.forEach(el => {
          const url = el.src || el.dataset.src || el.dataset.videoUrl || el.dataset.videoSrc;
          if (url && url.startsWith('http')) {
            videos.add({
              url,
              type: 'video',
              name: this.getFileName(url),
              size: '获取中...'
            });
          }
        });

        // 扫描 iframe
        document.querySelectorAll('iframe').forEach(iframe => {
          const src = iframe.src;
          if (src && this.isVideoURL(src)) {
            videos.add({
              url: src,
              type: 'video',
              name: this.getFileName(src),
              size: '获取中...'
            });
          }
        });

        resolve();
      });
    });

    this.resources.videos = Array.from(videos);
  }

  async scanAudios() {
    const audios = new Set();

    await new Promise(resolve => {
      requestIdleCallback(() => {
        document.querySelectorAll('audio, audio source').forEach(el => {
          const url = el.src || el.dataset.src;
          if (url && url.startsWith('http')) {
            audios.add({
              url,
              type: 'audio',
              name: this.getFileName(url),
              size: '获取中...'
            });
          }
        });
        resolve();
      });
    });

    this.resources.audios = Array.from(audios);
  }

  showLoading() {
    if (!this.resourceContainer) return;
    
    const loading = document.createElement('div');
    loading.className = 'loading';
    loading.textContent = '正在扫描资源';
    this.resourceContainer.innerHTML = '';
    this.resourceContainer.appendChild(loading);
  }

  isVideoURL(url) {
    if (!url) return false;
    const videoPatterns = [
      /youtube\.com\/watch/,
      /youtu\.be/,
      /vimeo\.com/,
      /dailymotion\.com/,
      /\.mp4(\?|$)/,
      /\.webm(\?|$)/,
      /\.ogg(\?|$)/
    ];
    return videoPatterns.some(pattern => pattern.test(url));
  }

  async updateResourceSizes() {
    const updateSize = async (resource) => {
      if (!resource.url) return;
      
      try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 5000);
        
        const response = await fetch(resource.url, { 
          method: 'HEAD',
          signal: controller.signal
        });
        
        clearTimeout(timeoutId);
        const size = response.headers.get('content-length');
        resource.size = size ? this.formatSize(parseInt(size)) : '未知大小';
      } catch {
        resource.size = '未知大小';
      }
    };

    const currentResources = this.resources[this.currentTab];
    const updatePromises = currentResources.map(updateSize);
    
    // 使用 Promise.allSettled 确保所有请求完成
    await Promise.allSettled(updatePromises);
    
    if (this.drawer.classList.contains('open')) {
      this.renderResources();
    }
  }

  formatSize(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  renderResources() {
    if (!this.resourceContainer) return;

    const resources = this.resources[this.currentTab];
    const fragment = document.createDocumentFragment();

    if (resources.length === 0) {
      const empty = document.createElement('div');
      empty.style.cssText = 'text-align:center;padding:20px;color:#666;';
      empty.textContent = '未找到资源';
      fragment.appendChild(empty);
    } else {
      resources.forEach(resource => {
        const item = this.createResourceItem(resource);
        fragment.appendChild(item);
      });
    }

    this.resourceContainer.innerHTML = '';
    this.resourceContainer.appendChild(fragment);

    // 延迟获取资源大小
    requestIdleCallback(() => this.updateResourceSizes());
  }

  createResourceItem(resource) {
    const item = document.createElement('div');
    item.className = 'resource-item';

    const preview = document.createElement(resource.type === 'image' ? 'img' : 'div');
    preview.className = 'resource-preview';
    if (resource.type === 'image') {
      preview.src = resource.url;
    } else {
      preview.textContent = resource.type === 'video' ? '视频文件' : '音频文件';
    }

    const info = document.createElement('div');
    info.className = 'resource-info';

    const name = document.createElement('div');
    name.className = 'resource-name';
    name.title = resource.name;
    name.textContent = resource.name;

    const size = document.createElement('div');
    size.className = 'resource-size';
    size.textContent = resource.size;

    info.appendChild(name);
    info.appendChild(size);

    const downloadBtn = document.createElement('button');
    downloadBtn.className = 'download-btn';
    downloadBtn.textContent = '下载';
    downloadBtn.addEventListener('click', () => this.downloadResource(resource));

    item.appendChild(preview);
    item.appendChild(info);
    item.appendChild(downloadBtn);

    return item;
  }

  getFileName(url) {
    try {
      const urlObj = new URL(url);
      const pathname = urlObj.pathname;
      const filename = pathname.split('/').pop() || '未命名文件';
      return filename.split('?')[0] || '未命名文件';
    } catch {
      return '未命名文件';
    }
  }

  async downloadResource(resource) {
    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 30000);

      const response = await fetch(resource.url, { signal: controller.signal });
      clearTimeout(timeoutId);

      const blob = await response.blob();
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = resource.name;
      a.style.display = 'none';
      document.body.appendChild(a);
      a.click();
      
      // 清理
      setTimeout(() => {
        window.URL.revokeObjectURL(url);
        document.body.removeChild(a);
      }, 100);
    } catch (error) {
      console.error('下载失败:', error);
      alert('下载失败，请检查网络连接或资源是否可用');
    }
  }

  downloadAll() {
    const resources = this.resources[this.currentTab];
    // 使用延迟下载避免浏览器卡死
    resources.forEach((resource, index) => {
      setTimeout(() => this.downloadResource(resource), index * 1000);
    });
  }
}

// 立即初始化插件
new ResourceCrawler(); 